﻿using System;
using System.Net;
using System.Text;
using System.Threading.Tasks;

namespace Songhay.Net
{
    /// <summary>
    /// Static methods for asynchronous HTTP operations.
    /// </summary>
    public static partial class HttpVerbAsyncUtility
    {
        /// <summary>
        /// Executes <see cref="System.Net.WebClient"/> GET operation.
        /// </summary>
        /// <param name="resourceIndicator">The resource indicator.</param>
        public static Task<string> GetAsync(Uri resourceIndicator)
        {
            return GetAsync(resourceIndicator, null);
        }

        /// <summary>
        /// Executes <see cref="System.Net.WebClient"/> GET operation.
        /// </summary>
        /// <param name="resourceIndicator">The resource indicator.</param>
        /// <param name="completedEventAction">The completed event action.</param>
        public static Task<string> GetAsync(Uri resourceIndicator, Action<object, DownloadStringCompletedEventArgs> completedEventAction)
        {
            var client = new WebClient();
            client.Encoding = Encoding.UTF8;

            return GetAsync(client, resourceIndicator, completedEventAction);
        }

        /// <summary>
        /// Executes <see cref="System.Net.WebClient"/> GET operation.
        /// </summary>
        /// <param name="client">The client.</param>
        /// <param name="resourceIndicator">The resource indicator.</param>
        /// <param name="completedEventAction">The completed event action.</param>
        /// <remarks>
        /// For details, see the “Converting an Event-Based Pattern” section in
        /// “Simplify Asynchronous Programming with Tasks”
        /// by Igor Ostrovsky
        /// [http://msdn.microsoft.com/en-us/magazine/ff959203.aspx]
        /// </remarks>
        public static Task<string> GetAsync(WebClient client, Uri resourceIndicator, Action<object, DownloadStringCompletedEventArgs> completedEventAction)
        {
            if (client == null) throw new ArgumentNullException("The expected Web Client is not here.");
            if (resourceIndicator == null) throw new ArgumentNullException("The expected URI is not here.");

            var completionSource = new TaskCompletionSource<string>();

            client.DownloadStringCompleted += (o, args) =>
            {
                try
                {
                    if (args.Error != null) completionSource.SetException(args.Error);
                    else if (args.Cancelled) completionSource.SetCanceled();
                    else
                    {
                        completionSource.SetResult(args.Result);
                        if (completedEventAction != null) completedEventAction.Invoke(o, args);
                    }
                }
                finally
                {
#if !SILVERLIGHT
                    client.Dispose();
#endif
                }
            };

            client.DownloadStringAsync(resourceIndicator);

            return completionSource.Task;
        }

        /// <summary>
        /// Executes <see cref="System.Net.WebClient" /> POST operation.
        /// </summary>
        /// <param name="client">The client.</param>
        /// <param name="resourceIndicator">The resource indicator.</param>
        /// <param name="postData">The post data.</param>
        public static Task<string> PostAsync(WebClient client, Uri resourceIndicator, string postData)
        {
            return PostAsync(client, resourceIndicator, postData, null);
        }

        /// <summary>
        /// Executes <see cref="System.Net.WebClient" /> POST operation.
        /// </summary>
        /// <param name="client">The client.</param>
        /// <param name="resourceIndicator">The resource indicator.</param>
        /// <param name="postData">The post data.</param>
        /// <param name="completedEventAction">The completed event action.</param>
        public static Task<string> PostAsync(WebClient client, Uri resourceIndicator, string postData, Action<object, UploadStringCompletedEventArgs> completedEventAction)
        {
            if (client == null) throw new ArgumentNullException("The expected Web Client is not here.");
            if (resourceIndicator == null) throw new ArgumentNullException("The expected URI is not here.");
            if (postData == null) throw new ArgumentNullException("The expected post data is not here.");

            var completionSource = new TaskCompletionSource<string>();

            client.UploadStringCompleted += (o, args) =>
            {
                try
                {
                    if (args.Error != null) completionSource.SetException(args.Error);
                    else if (args.Cancelled) completionSource.SetCanceled();
                    else
                    {
                        completionSource.SetResult(args.Result);
                        if (completedEventAction != null) completedEventAction.Invoke(o, args);
                    }
                }
                finally
                {
#if !SILVERLIGHT
                    client.Dispose();
#endif
                }
            };

            client.UploadStringAsync(resourceIndicator, postData);
            return completionSource.Task;
        }

#if !SILVERLIGHT

        /// <summary>
        /// Executes <see cref="System.Net.WebClient"/> POST operation.
        /// </summary>
        /// <param name="resourceIndicator">The resource indicator.</param>
        /// <param name="postData">The post data.</param>
        public static Task<string> PostJsonAsync(Uri resourceIndicator, string postData)
        {
            return PostJsonAsync(resourceIndicator, postData, null);
        }

        /// <summary>
        /// Executes <see cref="System.Net.WebClient"/> POST operation.
        /// </summary>
        /// <param name="resourceIndicator">The resource indicator.</param>
        /// <param name="postData">The post data.</param>
        /// <param name="completedEventAction">The completed event action.</param>
        public static Task<string> PostJsonAsync(Uri resourceIndicator, string postData, Action<object, UploadStringCompletedEventArgs> completedEventAction)
        {
            var client = new WebClient();
            client.Encoding = Encoding.UTF8;
            client.Headers.Add("Accept", "application/json, text/javascript, */*; q=0.01");
            client.Headers.Add("Accept-Encoding", "gzip, deflate");
            client.Headers.Add("Cache-Control", "no-cache");
            client.Headers.Add("Content-Type", "application/json; charset=utf-8");

            return PostAsync(client, resourceIndicator, postData);
        }
#endif
    }
}
